#include "astar.h"
#include <math.h>

int is_in_bound(s_case *cell)
{
    return (cell->x >= 0 && cell->x < MAT_H && cell->y >= 0 && cell->y < MAT_H);
}

int cellcmp (s_case *c1, s_case *c2)
{
    return (c1->x == c2->x && c1->y == c2->y);
}

int get_manhattan(s_case *start, s_case *end)
{
    return (sqrt(pow(end->x - start->x, 2) + pow(end->y - start->y, 2)));
}

s_case *create_case(int tab[2], int distt, s_case *dst,  s_case *prev)
{
    s_case *new;

    new = malloc(sizeof (s_case));
    new->x = tab[1];
    new->y = tab[0];
    new->manh = get_manhattan(new, dst);
    new->distt = distt;
    new->total = new->manh + new->distt;
    new->prev = prev;
    new->next = NULL;

    return (new);
}

s_case *create_srcdst(int tab[2], int manh, int distt, s_case *prev)
{
    s_case *new;

    new = malloc(sizeof (s_case));
    new->x = tab[1];
    new->y = tab[0];
    new->manh = manh;
    new->distt = distt;
    new->total = new->manh + new->distt;
    new->prev = prev;
    new->next = NULL;

    return (new);
}

s_case *get_lower_list(s_case *opened_list)
{
    s_case *min;

    min = get_min(opened_list);

    return (min);
}

void update_cost(s_case *old, s_case *new)
{
    if (new->total < old->total)
        edit_list(old, new->total, new->prev);
}

s_case *get_opened_list(s_case *current, char map[MAT_H][MAT_H],
        s_case *dst, s_case *opened_list, s_case *closed_list)
{
    int    tab[2];

    if (current->x + 1 < MAT_H && (map[current->y][current->x + 1] == 'a'
                ||  map[current->y][current->x + 1] == '1') &&
            !is_exist(closed_list, current->x + 1, current->y))
    {
        tab[1] = current->x + 1;
        tab[0] = current->y;
        if (!is_exist(opened_list, current->x + 1, current->y))
            add_list(&opened_list, create_case(tab, current->distt + 1, dst
                        , current));
    }
    if (current->y + 1 < MAT_H && (map[current->y + 1][current->x] == 'a'
                ||  map[current->y + 1][current->x] == '1') &&
            !is_exist(closed_list, current->x, current->y + 1))
    {
        tab[1] = current->x;
        tab[0] = current->y + 1;
        if (!is_exist(opened_list, current->x, current->y + 1))
            add_list(&opened_list, create_case(tab, current->distt + 1, dst
                        , current));
    }
    if (current->x - 1 >= 0 && (map[current->y][current->x - 1] == 'a'
                ||  map[current->y][current->x - 1] == '1') &&
            !is_exist(closed_list, current->x - 1, current->y))
    {
        tab[1] = current->x - 1;
        tab[0] = current->y;
        if (!is_exist(opened_list, current->x - 1, current->y))
            add_list(&opened_list, create_case(tab, current->distt + 1, dst
                        , current));
    }
    if (current->y - 1 >= 0 && (map[current->y - 1][current->x] == 'a'
                ||  map[current->y - 1][current->x] == '1')
            && !is_exist(closed_list, current->x, current->y - 1))
    {
        tab[1] = current->x;
        tab[0] = current->y - 1;
        if (!is_exist(opened_list, current->x, current->y - 1))
            add_list(&opened_list, create_case(tab, current->distt + 1, dst
                        , current));
    }

    return (opened_list);
}

s_case *path_finding(s_case *src, s_case *dst, char map[MAT_H][MAT_W])
{
    s_case *current;
    s_case *tmp;
    s_case *opened_list = NULL;
    s_case *closed_list = NULL;
    add_list(&closed_list, src);

    current = src;
    if (is_in_bound(src) && is_in_bound(dst))
    {
        while (!cellcmp(current, dst))
        {
            tmp = get_lower_list(get_opened_list(current, map, dst,
                        opened_list, closed_list));
            if (!tmp)
                return (closed_list);
            if (!is_exist(closed_list, tmp->x, tmp->y))
                add_list(&closed_list, tmp);
            current = tmp;
        }
        return (closed_list);
    }
    else
        return (NULL);
}

/**
** @brief search the shortest path from src to destinatino
**
** @param object object is a structure who contain the src and ths destination
**
** @return return a linked list with the shortest past
*/
s_case *get_astar(s_object *object)
{
    s_case *src;
    s_case *dst;
    s_case *path;

    src = create_srcdst(object->src, 0, 0, NULL);
    dst = create_srcdst(object->dst, 0, 0, NULL);

    path = path_finding(src, dst, object->mat);

    return (path);
}
